package main

import (
	"context"
	"flag"
	"gin-skeleton/core/logger"
	"gin-skeleton/support/cache"
	"github.com/spf13/cast"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"strconv"
	"syscall"
	"time"

	"gin-skeleton/etc"
	"gin-skeleton/router"
	"gin-skeleton/support/db"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
)

var (
	debugMode  bool
)

func main() {
	parseVar()
	// 日志
	initLogger()
	// 加载配置
	loadConfig()
	// 初始化应用
	initApp()
	// 初始化数据库
	initConnect()
	// 启动web服务
	startServer()
}

func parseVar() {
	debugMode = *flag.Bool("d", false, "Enable the debug")
	if !debugMode {
		debugMode = cast.ToBool(os.Getenv("APP_DEBUG"))
	}

	flag.Parse()
}

func initLogger(){
	// 设置日志保存方式，按日期分文件存储
	path := filepath.Join("./runtime/logs/log")
	logger.UseRotateLogs(path, []logrus.Level{
		logrus.InfoLevel,
		logrus.WarnLevel,
		logrus.ErrorLevel,
		logrus.FatalLevel,
		logrus.PanicLevel,
	})
}

// 加载配置文件
func loadConfig() {

	// 设置运行模式
	if debugMode {
		gin.SetMode(gin.DebugMode)
	} else {
		gin.SetMode(gin.ReleaseMode)
	}
	etc.InitConfig()

	logger.LogAddCurrentVersion(etc.Load().App.Version)
}

// 初始化应用
func initApp() {
	// 设置CPU核心数
	c := etc.Load()
	if c.App.Cpu == 0 {
		c.App.Cpu = runtime.NumCPU()
		etc.Store(c)
	}
	runtime.GOMAXPROCS(c.App.Cpu)
}

// 初始化数据库连接
func initConnect() {
	db.InitDbConnect()
	cache.InitRedisConnect()
}

// 启动服务
func startServer() {
	r := gin.Default()
	router.InitApiRouter(r)
	router.InitWebRouter(r)

	srv := &http.Server{
		Addr:    ":" + strconv.Itoa(etc.Configure.App.Port),
		Handler: r,
	}

	go func() {
		// 异常捕获
		defer func() {
			err := recover()
			log.Println(err)
			debug.PrintStack()
		}()
		// 服务连接
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logrus.Fatalf("listen: %s\n", err)
		}
	}()

	// 等待中断信号以优雅地关闭服务器（设置 5 秒的超时时间）
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, os.Kill, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM) // 监听可能的退出信号
	received := <-quit                                                                           //接收信号管道中的值
	logrus.Warnln("信号值", received.String())
	logrus.Info("Shutdown server ...")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Println("Server exiting")

}
